#include "dkglFont.h"
#include "dkglLog.h"

namespace DKGL
{

using namespace std;

FontManager::FontManager(HDC hdc)
{
	addNewFont("Default", hdc, "Arial");
}

FontManager::~FontManager()
{
	map<string, Font*>::iterator it;

	for(it=mFont.begin();it!=mFont.end();it++)
		delete it->second;
}

Font *FontManager::_createFont(HDC hdc, const char *typeface, int height,
		            int weight, DWORD italic)
{
	Font	*font = NULL;				// Font data pointer 
    HFONT	fontid;				// Windows font ID 
    int		charset;			// Character set code 

    // Allocate memory 
    font = new Font();
	if(!font)
	{
		Log::dump("Allocate memory to font fail.");
		return NULL;
	}

    // Allocate display lists 
    if ((font->base = glGenLists(256)) == 0)
	{
        delete font;
		Log::dump("Allocate display lists fail.");
        return NULL;
    }

    /* Select a character set */
    if (_stricmp(typeface, "symbol") == 0)
        charset = SYMBOL_CHARSET;
    else
        charset = ANSI_CHARSET;

    // Load the font 
    fontid = CreateFont(height, 0, 0, 0, weight, italic, FALSE, FALSE,
                        charset, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
                        DRAFT_QUALITY, DEFAULT_PITCH, reinterpret_cast<LPCSTR>(typeface));

    SelectObject(hdc, fontid);

    // Create bitmaps for each character 
    wglUseFontBitmaps(hdc, 0, 256, font->base);

    // Get the width and height information for each character 
	GetCharWidth(hdc, 0, 255, font->mCharWidths);
	font->mCharHeight= height;

    return (font);
}

void FontManager::_destroyFont(Font *font)
{
	if (!font)
        return;

    glDeleteLists(font->base, 256);
    delete font;
}

void FontManager::setFontColor(const std::string& font_name, float r, float g, float b)
{
	mFont[font_name]->mColor[0] = r;
	mFont[font_name]->mColor[1] = g;
	mFont[font_name]->mColor[2] = b;
}

void FontManager::_putsFont(Font *font, const char *s)
{
	if (!font|| !s)
	{
		Log::dump("font ptr or s is NULL.");
        return;
	}
    glPushAttrib(GL_LIST_BIT);
    glListBase(font->base);
    glCallLists((GLsizei)strlen(s), GL_UNSIGNED_BYTE, s);
    glPopAttrib();
}

/*---------------------------------------------------------------------------------------------------------------------
Add a new font (font-type) to the engine
[IN] 
hDC : the handle of the device contex
typeface : default is Arial
height		: font height in pixel
weight		: don't care = 0; normal  = 400; bold = 700; ultra bold = 800 (see MSDN CreateFont)
italic			: TRUE of FALSE
r, g, b		: default is white
[OUT]
...
[RETURN]
DKFONTid	: the ID of the font, negtive value = failed.
----------------------------------------------------------------------------------------------------------------------*/
bool FontManager::addNewFont(const std::string& font_name, HDC hdc, const char *typeface,
		int height, FONT_TYPE weight,DWORD  italic)
{
	char _typeface[16];
	
	// check name collision
	if(mFont.find(font_name)!=mFont.end())
		return false;

	if(typeface == NULL)
		sprintf(_typeface, "Arial");
	else
		sprintf(_typeface, "%s", typeface);

	mFont[font_name] = _createFont(hdc, _typeface, height, weight, italic);

	if(!mFont[font_name])
	{
		mFont.erase(font_name);
		return false;
	}

	return true;
	
	
}

/*-----------------------------------------------------------
-----------------------------------------------------------*/
void FontManager::begin(const Viewport& vp)
{
	glViewport(vp.x, vp.y, vp.width, vp.height);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
    glLoadIdentity();
	glOrtho((GLdouble)0, (GLdouble)vp.width,
		(GLdouble)vp.height, (GLdouble)0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
}

void FontManager::printf(const std::string& msg,  int x, int y, MSG_ALIGNMENT align,const std::string& font_name)
{
	// check exist
	if(mFont.find(font_name)==mFont.end())
		return;
	 
	//va_list ap;						// Argument pointer
	//unsigned char s[1024], *ptr;	// output string
	int width, i;

	//va_start(ap, format);
    //vsprintf((char *)s, format, ap);
    //va_end(ap);

	// Figure out the width of the string in pixels... 
    //for (ptr = s, width = 0; *ptr; ptr ++)
	//	width += mFont[font_name]->mCharWidths[*ptr];
	
	for(i=0, width = 0; static_cast<unsigned int>(i)<msg.size();i++)
		width += mFont[font_name]->mCharWidths[msg[i]];


	glPushAttrib(GL_LIGHTING_BIT);
	glDisable(GL_LIGHTING);

	glColor3fv(mFont[font_name]->mColor);
	glRasterPos2i(x, y);

	// Adjust the bitmap position as needed to justify the text 
    if (align == MA_ALIGN2RIGHT)
        glBitmap(0, 0, 0, 0, (GLfloat)-width, 0, NULL);
    else if (align == MA_ALIGN2CENTER)
        glBitmap(0, 0, 0, 0, (GLfloat)-width / 2, 0, NULL);

	_putsFont(mFont[font_name], msg.c_str());
	glPopAttrib();
}

void FontManager::end()
{
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
}

}